#include "tcpclient.h"

#include <utility>

TcpClient::TcpClient(QWidget *parent)
{
    // 更改大小时不重新绘制
    setAttribute(Qt::WA_StaticContents);
    isConnected = false;
    isCurrentPainter = false;
    isDrawing = false;
    image = new QImage(540, 490, QImage::Format_RGB32);
    // qDebug() << image->isNull();
    image->fill(Qt::white);
    update();
}

void TcpClient::setServerInfo(QString ip, int port, QString name)
{
    serverAddress = std::move(ip);
    serverPort = port;
    username = std::move(name);
}

bool TcpClient::getIsCurrentPainter() const
{
    return isCurrentPainter;
}

void TcpClient::drawLine(const QPoint &endPoint)
{
    if(!isCurrentPainter)
        return;
    QPainter painter(image);
    // 设置抗锯齿
    painter.setRenderHint(QPainter::Antialiasing);
    // 设定画笔
    painter.setPen(QPen(penColor, penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    // 绘制线条
    painter.drawLine(lastPoint, endPoint);
    int rad = (penWidth / 2) + 2;
    update(QRect(lastPoint, endPoint).normalized().adjusted(-rad, -rad, +rad, +rad));
    // 如果是画家，发送绘制消息给服务端
    if(isConnected && isCurrentPainter)
    {
        sendMsg(2, lastPoint, endPoint);
    }
    lastPoint = endPoint;
}

void TcpClient::resizeImage(QImage* image, const QSize &newSize)
{
    // 如果新的大小与旧的大小一致，什么都不做
    if(image->size() == newSize)
        return;
    // 生成新的画板
    QImage newImage(newSize, QImage::Format_RGB32);
    newImage.fill(qRgb(255, 255, 255));
    QPainter painter(&newImage);
    // 把之前的图形绘制到新的画板上
    painter.drawImage(QPoint(0, 0), *image);
    *image = newImage;
}

void TcpClient::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QRect dirtyRect = event->rect();
    painter.drawImage(dirtyRect, *image, dirtyRect);
}

void TcpClient::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        isDrawing = true;
        lastPoint = event->pos();
    }
}

void TcpClient::mouseMoveEvent(QMouseEvent *event)
{
    if((event->buttons() & Qt::LeftButton) && isDrawing)
        drawLine(event->pos());
}

void TcpClient::mouseReleaseEvent(QMouseEvent *event)
{
    if((event->buttons() & Qt::LeftButton) && isDrawing)
    {
        drawLine(event->pos());
        isDrawing = false;
    }
}

void TcpClient::resizeEvent(QResizeEvent *event)
{
    if(width() > image->width() || height() > image->height())
    {
        int newWidth = qMax(width() + 128, image->width());
        int newHeight = qMax(height() + 128, image->height());
        resizeImage(image, QSize(newWidth, newHeight));
        update();
    }
    QWidget::resizeEvent(event);
}

void TcpClient::setPenColor(const QColor &newPenColor)
{
    penColor = newPenColor;
}

void TcpClient::setPenWidth(int newPenWidth)
{
    penWidth = newPenWidth;
}

void TcpClient::connectToServer()
{
    clientSocket = new QTcpSocket(this);
    // qDebug() << serverAddress << ", " << serverPort;
    clientSocket->connectToHost(serverAddress, serverPort);
    connect(clientSocket, &QIODevice::readyRead, this, &TcpClient::receiveMsg);
    // 判断是否连接成功
    // isConnected = clientSocket->waitForConnected(5000);
}

void TcpClient::disconnectFromServer()
{
    if(isConnected)
    {
        clientSocket->disconnectFromHost();
        isConnected = false;
        isCurrentPainter = false;
    }
}

// 接收消息的函数
void TcpClient::receiveMsg()
{
    QByteArray datagram = clientSocket->readAll();
    QList<QByteArray> msgSplitList;
    QString message;
    // qDebug() << datagram;
    // 因为客户端会一直不断接收消息，多条消息会产生碰撞
    // 根据消息类型分别处理，将自身所需的消息裁剪掉之后再重新判断消息类型
    CheckAnotherMsg:
    // 有新用户
    if(datagram.at(0) == '1')
    {
        msgSplitList = datagram.split(';');
        for(int i = 1; i < msgSplitList.size(); ++i)
        {
            message.append(msgSplitList.at(i));
            message.append(';');
        }
        // qDebug() << message;
        emit signalNewUser(message);
        message.clear();
        if(msgSplitList.at(2) != "")
        {
            datagram.clear();
            for(int i = 2; i < msgSplitList.size() - 1; ++i)
            {
                datagram.append(msgSplitList.at(i));
                datagram.append(';');
            }
            goto CheckAnotherMsg;
        }
    }
    // 接收绘制信息并进行绘制
    else if(datagram.at(0) == '2')
    {
        if(!isCurrentPainter)
        {
            msgSplitList = datagram.split(';');
            QPainter painter(image);
            // 设置抗锯齿
            painter.setRenderHint(QPainter::Antialiasing);
            painter.setPen(QPen(QColor(msgSplitList.at(1).data()), msgSplitList.at(2).toInt(), Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
            painter.drawLine(QPoint(msgSplitList.at(3).toInt(), msgSplitList.at(4).toInt()), QPoint(msgSplitList.at(5).toInt(), msgSplitList.at(6).toInt()));
            int rad = (penWidth / 2) + 2;
            update(QRect(QPoint(msgSplitList.at(3).toInt(), msgSplitList.at(4).toInt()), QPoint(msgSplitList.at(5).toInt(), msgSplitList.at(6).toInt())).normalized().adjusted(-rad, -rad, +rad, +rad));
            if(msgSplitList.at(7) != "")
            {
                datagram.clear();
                for(int i=7; i < msgSplitList.size() - 1; ++i)
                {
                    datagram.append(msgSplitList.at(i));
                    datagram.append(';');
                }
                goto CheckAnotherMsg;
            }
        }
    }
    // 有来自其他用户的消息
    else if(datagram.at(0) == '3')
    {
        msgSplitList = datagram.split(';');
        message.append(msgSplitList.at(1));
        message.append(": ");
        message.append(msgSplitList.at(2));
        emit signalNewMsg(message);
        message.clear();
        if(msgSplitList.at(3) != "")
        {
            datagram.clear();
            for(int i = 3; i < msgSplitList.size() - 1; ++i)
            {
                datagram.append(msgSplitList.at(i));
                datagram.append(';');
            }
            goto CheckAnotherMsg;
        }
    }
    // 清屏
    else if(datagram.at(0) == '4')
    {
        image->fill(qRgb(255, 255, 255));
        update();
        msgSplitList = datagram.split(';');
        if(msgSplitList.at(1) != "")
        {
             datagram.clear();
             for(int i = 1; i < msgSplitList.size() - 1; ++i)
             {
                  datagram.append(msgSplitList.at(i));
                  datagram.append(';');
             }
        goto CheckAnotherMsg;
        }
    }
    // 接收词语，成为画家
    else if(datagram.at(0) == '5')
    {
        isGamePlaying = true;
        isCurrentPainter = true;
        msgSplitList = datagram.split(';');
        emit signalNewWord(msgSplitList.at(1));
        clearImage();
        if(msgSplitList.at(2) != "")
        {
            datagram.clear();
            for(int i=2; i<msgSplitList.size()-1; ++i)
            {
                datagram.append(msgSplitList.at(i));
                datagram.append(';');
            }
            goto CheckAnotherMsg;
        }
    }
    // 切换画家
    else if(datagram.at(0) == '6')
    {
        isCurrentPainter = false;
        setCursor(Qt::ArrowCursor);
        msgSplitList = datagram.split(';');
        emit signalCancelPainter();
        if(msgSplitList.at(1) != "")
        {
            datagram.clear();
            for(int i=1; i<msgSplitList.size()-1; ++i)
            {
                datagram.append(msgSplitList.at(i));
                datagram.append(';');
            }
            goto CheckAnotherMsg;
        }
    }
    // 剩余时间
    else if(datagram.at(0) == '7')
    {
        isGamePlaying = true;
        msgSplitList = datagram.split(';');
        emit signalNewTime(msgSplitList.at(1));
        if(msgSplitList.at(2) != "")
        {
            datagram.clear();
            for(int i=2; i<msgSplitList.size()-1; ++i)
            {
                datagram.append(msgSplitList.at(i));
                datagram.append(';');
            }
            goto CheckAnotherMsg;
        }
    }
    // 游戏结果
    else if(datagram.at(0) == '9')
    {
        msgSplitList = datagram.split(';');
        message.append(msgSplitList.at(1));
        message.append(" 猜对了！答案是<font><b>");
        message.append(msgSplitList.at(2));
        message.append("</b></font>。");
        emit signalBeGuessed(message);
        message.clear();
        if(msgSplitList.at(3) != "")
        {
            datagram.clear();
            for(int i=3; i<msgSplitList.size()-1; ++i)
            {
                datagram.append(msgSplitList.at(i));
                datagram.append(';');
            }
            goto CheckAnotherMsg;
        }
    }
    // 用户下线
    else if(datagram.at(0) == '0')
    {
        msgSplitList = datagram.split(';');
        emit signalUserLeft(msgSplitList.at(1).toInt(), msgSplitList.at(2));
        if(msgSplitList.at(3) != "")
        {
            datagram.clear();
            for(int i=3; i<msgSplitList.size()-1; ++i)
            {
                datagram.append(msgSplitList.at(i));
                datagram.append(';');
            }
            goto CheckAnotherMsg;
        }
    }
}

// 清屏
void TcpClient::sendMsg(int type)
{
    if(isConnected && type == 4 && isCurrentPainter)
    {
        QByteArray datagram("4;");
        clientSocket->write(datagram);
        // qDebug() << datagram;
    }
}
// 发言
void TcpClient::sendMsg(int type, const QString& name, const QString& word)
{
    if(isConnected && type == 3 && !isCurrentPainter)
    {
        QByteArray datagram("3;");
        datagram.append(name.toUtf8());
        datagram.append(';');
        datagram.append(word.toUtf8());
        datagram.append(';');
        clientSocket->write(datagram);
        // qDebug() << datagram;
    }
}
// 绘制
void TcpClient::sendMsg(int type, QPoint start, QPoint end)
{
    if(isConnected && type == 2 && isCurrentPainter)
    {
        QByteArray datagram("2;");
        // 将 QString 类型转换为 QByteArray 类型
        datagram.append(penColor.name().toUtf8());
        datagram.append(';');
        // 将 int 转换为 char 类型
        datagram.append(QString::number(penWidth).toUtf8());
        datagram.append(';');
        // qDebug() << start.x();
        datagram.append(QString::number(start.x()).toUtf8());
        datagram.append(';');
        datagram.append(QString::number(start.y()).toUtf8());
        datagram.append(';');
        datagram.append(QString::number(end.x()).toUtf8());
        datagram.append(';');
        datagram.append(QString::number(end.y()).toUtf8());
        datagram.append(';');
        clientSocket->write(datagram);
        // qDebug() << datagram;
    }
}
// 发送用户名、弃权
void TcpClient::sendMsg(int type, const QString& name)
{
    if(type == 1 || type == 8)
    {
        QByteArray datagram;
        datagram.append(QString::number(type).toUtf8());
        datagram.append(';');
        datagram.append(name.toUtf8());
        datagram.append(';');
        clientSocket->write(datagram);
        // qDebug() << datagram;
    }
}

void TcpClient::clearImage()
{
    // 未连接状态，只清空画板
    if(!isConnected)
    {
        image->fill(qRgb(255, 255, 255));
        update();
    }
    // 如果是画家，清空画板的同时发送消息
    else if(isConnected && isCurrentPainter)
    {
        image->fill(qRgb(255, 255, 255));
        update();
        sendMsg(4);
    }
}

void TcpClient::setPencilCursor()
{
    setCursor(Qt::CrossCursor);
}

void TcpClient::setEraserCursor()
{
    QCursor cursor;
    QPixmap pixmap("://images/eraser.png");
    pixmap = pixmap.scaled(32, 32, Qt::KeepAspectRatio);
    cursor = QCursor(pixmap);
    setCursor(cursor);
}
